<?php

namespace framework\system\manager;

use framework;
use framework\system\kernel\Manager;
use framework\system\kernel\CFile;
use framework\system\kernel\Conversion;

/**
 * 
 * @version 1.0.0
 * @author vampire
 */
class ComponentManager extends Manager {

    /**
     *
     * @var array $component_map 组件地图
     * [
     *      'system.web.webApplication' => [
     *          'Class' => 'cong\\web\\CWebApplication',
     *          'File' => FRAMEWORK . DS . 'web' . DS . 'CWebApplication' . EXT,
     *          'Cover' => 'system.application',
     *     ]
     * ]
     */
    protected $mapping_component = [];
    protected $kernel_is_loaded = false;
    protected $components = [];
    protected $components_alias = [];

    public function init() {

        $this->addMappingFile([
            DIR_FRAMEWORK . DS . "config" . DS . "mapping" . DS . "component" . EXT,
            DIR_APPLICATION . DS . "config" . DS . "mapping" . DS . "component" . EXT
        ]);
        $this->loadCoreComponent();
    }

    //映射处理函数
    public function processMapping($_mapping = NULL) {



        if (is_null($_mapping)) {
            return FALSE;
        }

        foreach ($_mapping as $k => $v) {
            if (array_key_exists("Class", $v)) {
                $this->mapping_component[$k] = $v;
            }
        }

        return TRUE;
    }

    /**
     * 
     * @param type $component
     * @return string success
     * @return false faile
     */
    public function registerComponent($component) {
        if (is_array($component)) {

            $component_name = $component["Component"];
            if (!($this->isComponentName($component_name))) {
                $error = "Component name $component_name is not start of \"com.\"";
            }
            if (!isset($component["Class"])) {
                $error = "Component  $component_name Class is not set";
            }

            /**
             * Component Register start;
             */
            $this->mapping_component[$component_name] = [];

            $this->mapping_component[$component_name]["Class"] = $component["Class"];

            if (isset($component["File"])) {
                $this->mapping_component[$component_name]["File"] = $component["File"];
            }
            if (isset($component["Cover"])) {
                $this->mapping_component[$component_name]["Cover"] = $component["Cover"];
            }
            if (isset($component["Alias"])) {
                $this->mapping_component[$component_name]["Alias"] = $component["Alias"];
            }
            return $component_name;
        }
        return FALSE;
    }

    public function load($component, $argv = null) {

        if ($this->isComponentName($component)) {
            if ($this->cmpExists($component)) {
                return TRUE;
            }

            $component_name = $component;
            if (!isset($this->mapping_component[$component_name])) {
                return FALSE;
            }
            if (isset($this->mapping_component[$component_name]['File'])) {
                CFile::requireFile($this->mapping_component[$component_name]['File']);
            }
            /**
             * ['component'=>'test','class'=>'test','file'=>'test.php']
             */
            $class = $this->mapping_component[$component_name]['Class'];

            if (!isset($this->components[$component_name])) {

                if (class_exists($class, TRUE)) {

                    $this->components[$component_name] = new $class($argv);
                    /*
                     * 设置组建覆盖
                     */
                    if (isset($this->mapping_component[$component_name]["Cover"])) {
                        $this->setCover($component_name, $this->mapping_component[$component_name]["Cover"]);
                    }

                    /*
                     * 设置组建别名
                     */
                    if (isset($this->mapping_component[$component_name]["Alias"])) {
                        $this->setAlias($component_name, $this->mapping_component[$component_name]["Alias"]);
                    }
                } else {
                    if (_DEBUG) {
                        echo "<br/>Notice:Component class [{$class}] not found <br/>";
                    }
                    return FALSE;
                }
            }
            return TRUE;
        }

        if (is_array($component)) {
            foreach ($component as $name => $value) {
                $this->load($value);
            }
        }
        return TRUE;
    }

    /*
     * 覆盖
     */

    protected function setCover($component_name, $cover) {
        if (empty($cover)) {
            return FALSE;
        }
        if (is_string($cover)) {
            if (isset($this->components[$cover])) {
                unset($this->components[$cover]);
            }
            $this->components[$cover] = $component_name;
        }
        if (is_array($cover) || is_object($cover)) {
            foreach ($cover as $_cover) {
                $this->setCover($component_name, $_cover);
            }
        }
    }

    /**
     * 别名
     */
    protected function setAlias($component_name, $alias) {


        if (is_string($alias)) {
            if ($this->isComponentName($component_name) && $this->isComponentName($alias)) {
                array_push($this->components_alias, [$alias, $component_name]);
            }
        }
        if (is_array($alias)) {
            foreach ($alias as $v) {
                $this->setAlias($component_name, $v);
            }
        }
    }

    public function coreComponents() {
        $components = [];
        foreach ($this->mapping_component as $k => $v) {
            if (array_key_exists("Autoload", $v)) {
                $components[] = $k;
            }
        }
        return $components;
    }

    /**
     * 加载核心组件
     * @return boolean
     */
    public function loadCoreComponent() {
        framework::mm()->send("message.framework.ready", TRUE);
        if ($this->kernel_is_loaded) {
            return FALSE;
        }

        $coreComponents = $this->coreComponents();
        $this->load($coreComponents);
        $this->kernel_is_loaded = TRUE;
        framework::mm()->send("message.framework.ready", TRUE);
        return TRUE;
    }

    public function &get($cmp = "com.framework") {
        //等待添加检查依赖功能

        foreach ($this->components_alias as $alias) {
            if ($cmp == $alias[0]) {
                $cmp = $alias[1];
            }
        }
        $this->load($cmp);
        if ($this->isComponentName($cmp)) {
            if (array_key_exists($cmp, $this->components)) {
                return $this->components[$cmp];
            }
        }
        return $cmp;
    }

    public function cmpExists($cmp) {
        if (!isset($this->components[$cmp])) {

            foreach ($this->components_alias as $alias) {
                if ($cmp == $alias[0]) {
                    return true;
                }
            }

            return FALSE;
        }
        if (is_object($this->components[$cmp])) {
            return TRUE;
        }
        return FALSE;
    }

}
